﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Globalization;
using CLFramework.Text;

namespace CLFramework.Web
{
    public static class StringExtension
    {
        private static readonly Regex WebUrlExpression = new Regex(@"(http|https)://(([\w-]+\.)+[\w-]+)(/[\w- ./?%&=]*)?", RegexOptions.Singleline | RegexOptions.Compiled);
        private static readonly Regex EmailExpression = new Regex(@"^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$", RegexOptions.Singleline | RegexOptions.Compiled);
        private static readonly Regex StripHTMLExpression = new Regex("<\\S[^><]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);

        private static readonly char[] IllegalUrlCharacters = new[] { ';', '/', '\\', '?', ':', '@', '&', '=', '+', '$', ',', '<', '>', '#', '%', '.', '!', '*', '\'', '"', '(', ')', '[', ']', '{', '}', '|', '^', '`', '~', '–', '‘', '’', '“', '”' };
        
        public static bool IsWebUrl(this string target)
        {
            return !string.IsNullOrEmpty(target) && WebUrlExpression.IsMatch(target);
        }

        public static string GetUrlDomain(this string url)
        {
            if (WebUrlExpression.IsMatch(url))
            {
                Match m = WebUrlExpression.Match(url);
                return (m.Groups[2].Value);
            }
            return null;
        }

        public static bool IsEmail(this string target)
        {
            return !string.IsNullOrEmpty(target) && EmailExpression.IsMatch(target);
        }

        public static string FormatWith(this string target, params object[] args)
        {
            Check.Argument.IsNotEmpty(target, "target");

            return string.Format(CultureInfo.CurrentCulture, target, args);
        }

        public static string WrapAt(this string target, int index)
        {
            const int DotCount = 3;

            Check.Argument.IsNotEmpty(target, "target");
            Check.Argument.IsNotNegativeOrZero(index, "index");

            return (target.Length < index) ? target : string.Concat(target.Substring(0, index), new string('.', DotCount));
        }

        public static string StripHtml(this string target)
        {
            return StripHTMLExpression.Replace(target, string.Empty);
        }

        public static string ToLegalUrl(this string target)
        {
            if (string.IsNullOrEmpty(target))
            {
                return target;
            }

            target = target.Trim();

            if (target.IndexOfAny(IllegalUrlCharacters) > -1)
            {
                foreach (char character in IllegalUrlCharacters)
                {
                    target = target.Replace(character.ToString(CultureInfo.CurrentCulture), string.Empty);
                }
            }

            target = target.Replace(" ", "-");

            while (target.Contains("--"))
            {
                target = target.Replace("--", "-");
            }

            return target;
        }

        public static string ToPlural(this string noun)
        {
            return PluralizerHelper.ToPlural(noun);
        }

        public static string ToSingular(this string noun)
        {
            return PluralizerHelper.ToSingular(noun);
        }

        public static string UrlEncode(this string target)
        {
            return HttpUtility.UrlEncode(target).Replace("+", "%20");
        }

        public static string UrlDecode(this string target)
        {
            return HttpUtility.UrlDecode(target);
        }

        public static string AttributeEncode(this string target)
        {
            return HttpUtility.HtmlAttributeEncode(target);
        }

        public static string HtmlEncode(this string target)
        {
            return HttpUtility.HtmlEncode(target);
        }

        public static string HtmlDecode(this string target)
        {
            return HttpUtility.HtmlDecode(target);
        }

        #region ulong GetNumberOfTextEnd

        /// <summary>
        /// 从字符串中的结尾取得指定长度无符号数字。
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="length">要取得数字的位数，如果为0则表示不知道位数将取得结尾的所有数字部分，在匹配成功后会将
        /// 此变量置为实际取得的数字。</param>
        /// <param name="prefixText">存放除去取出数字后字符串的变量。</param>
        /// <param name="number">存放结果数字。</param>
        /// <example>
        /// string s = "MB2A100105";<br/>
        /// string s1;<br/>
        /// ulong l;<br/>
        /// GetNumberOfTextEnd(s, 0, out s1, out l); //l=100105<br/>
        /// GetNumberOftestEnd(s, 6, out s1, out l); //l=100105<br/>
        /// GetNumberOfTextEnd(s, 3, out s1, out l); //l=105<br/>
        /// </example>
        /// <returns></returns>
        public static void GetNumberOfTextEnd(string text, ref int length, out string prefixText, out ulong number)
        {
            string expresssion = @"[0-9]{{{0}}}$";
            if (length <= 0)
            {
                expresssion = string.Format(expresssion, "1,");
            }
            else
            {
                expresssion = string.Format(expresssion, length);
            }

            Match match = Regex.Match(text, expresssion, RegexOptions.RightToLeft);
            if (match.Success)
            {
                number = ulong.Parse(match.Value);
                prefixText = text.Substring(0, match.Index);
                length = match.Length;
            }
            else
            {
                throw new Exception("Cannot found any number in text end."); //无法在文本结尾找到数字。
            }
        }

        /// <summary>
        /// 从字符串中的结尾取得指定长度无符号数字。
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="length">要取得数字的位数，如果为0则表示不知道位数将取得结尾的所有数字部分，在匹配成功后会将
        /// 此变量置为实际取得的数字。</param>
        /// <param name="prefixText">存放除去取出数字后字符串的变量。</param>
        /// <example>
        /// string s = "MB2A100105";<br/>
        /// string s1;<br/>
        /// ulong l;<br/>
        /// GetNumberOfTextEnd(s, 0, out s1, out l); //l=100105<br/>
        /// GetNumberOftestEnd(s, 6, out s1, out l); //l=100105<br/>
        /// GetNumberOfTextEnd(s, 3, out s1, out l); //l=105<br/>
        /// </example>
        /// <returns>结果数字。</returns>
        public static ulong GetNumberOfTextEnd(string text, ref int length, out string prefixText)
        {
            ulong result;
            GetNumberOfTextEnd(text, ref length, out prefixText, out result);
            return result;
        }

        /// <summary>
        /// 从字符串中的结尾取得指定长度无符号数字。
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="length">要取得数字的位数，如果为0则表示不知道位数将取得结尾的所有数字部分，在匹配成功后会将
        /// 此变量置为实际取得的数字。</param>
        /// <example>
        /// string s = "MB2A100105";<br/>
        /// string s1;<br/>
        /// ulong l;<br/>
        /// GetNumberOfTextEnd(s, 0, out s1, out l); //l=100105<br/>
        /// GetNumberOftestEnd(s, 6, out s1, out l); //l=100105<br/>
        /// GetNumberOfTextEnd(s, 3, out s1, out l); //l=105<br/>
        /// </example>
        /// <returns>结果数字。</returns>
        public static ulong GetNumberOfTextEnd(string text, ref int length)
        {
            ulong result;
            string prefixText; //存放除去取出数字后字符串的变量。

            GetNumberOfTextEnd(text, ref length, out prefixText, out result);

            return result;
        }

        /// <summary>
        /// 从字符串中的结尾取得指定长度无符号数字。
        /// </summary>
        /// <param name="text">结尾包含数字的字符串
        /// 此变量置为实际取得的数字。</param>
        /// <example>
        /// string s = "MB2A100105";<br/>
        /// string s1;<br/>
        /// ulong l;<br/>
        /// GetNumberOfTextEnd(s, 0, out s1, out l); //l=100105<br/>
        /// GetNumberOftestEnd(s, 6, out s1, out l); //l=100105<br/>
        /// GetNumberOfTextEnd(s, 3, out s1, out l); //l=105<br/>
        /// </example>
        /// <returns>结果数字。</returns>
        public static ulong GetNumberOfTextEnd(string text)
        {
            int length = 0;//要取得数字的位数，如果为0则表示不知道位数将取得结尾的所有数字部分，在匹配成功后会将
            //此变量置为实际取得的数字。
            ulong result;
            string prefixText; //存放除去取出数字后字符串的变量。

            GetNumberOfTextEnd(text, ref length, out prefixText, out result);

            return result;
        }

        #endregion
    }
}
